class IUP_DROP_BUTTON
--  Creates an interface element that is a button with a drop down arrow. It 
--  can function as a button and as a dropdown. Its visual presentation can 
--  contain a text and/or an image.
--
-- When dropped displays a child inside a dialog with no decorations, so it can 
-- simulate the initial function of a dropdown list, but it can display any 
-- layout of IUP elements inside the dropped dialog. When the user click 
-- outside the dialog, it is automatically closed.
--
-- It inherits from IUP_CANVAS.
--
-- Callbacks:
--
-- Inherits all callbacks of the IUP_CANVAS, but redefines a few of them. 
-- Including ACTION, BUTTON_CB, MOTION_CB, FOCUS_CB, LEAVEWINDOW_CB, and 
-- ENTERWINDOW_CB. To allow the application to use those callbacks the same 
-- callbacks are exported with the "FLAT_" prefix using the same parameters, 
-- except the FLAT_ACTION callback that now mimics the IupButton ACTION. They 
-- are all called before the internal callbacks and if they return IUP_IGNORE 
-- the internal callbacks are not processed.
--
-- Notes:
--
-- The natural size will be a combination of the size of the image and the 
-- title, if any, plus PADDING and SPACING (if both image and title are 
-- present), and plus the horizontal space occupied by the arrow.
--
-- The drop dialog is configured with no decorations and it is not resizable, 
-- and to close when loss the focus or when the user press the ESC key. It is a 
-- regular IUP_DIALOG. To obtain the drop button widget from the widget of the 
-- dialog call "drop_button" at the dialog. After performing some operation on 
-- the drop child, use set_show_drop_down=False on the drop button, you may 
-- also update its TITLE, just like a regular IUP_LIST with set_drop_down=True, 
-- but this will not be performed automatically by the drop button. For example,
--	set the ACTION callback on the IUP_LIST used as drop child:	
--
--	list_action (text: STRING; item, state: INTEGER): STRING
--    local
--      a_drop_button: IUP_DROP_BUTTON
--    do
--      if state.is_equal(1) then
--         a_drop_button := list.get_dialog.get_drop_button
--         a_drop_button.set_show_drop_down(False)
--         a_drop_button.set_title(text)
--	     end
--
--      Result := "IUP_DEFAULT"
--    end
--
-- Additionally to mimic a IUP_LIST with set_drop_down=True set 
-- set_border=True and set_drop_on_arrow=False on the drop button. But notice 
-- that the natural size will not use the largest item in the drop child list, 
-- so you can use EXPAND=HORIZONTAL or set VISIBLECOLUMNS, both on the drop 
-- button.	
	
inherit
	IUP_CANVAS
		redefine
			set_border,
			set_can_focus,
			set_expand,
			execute_flat_action,
			execute_dropdown,
			execute_dropshow,
			execute_flat_button,
			execute_flat_motion,
			execute_flat_focus,
			execute_flat_enterwindow,
			execute_flat_leavewindow
		end
	IUP_WIDGET_FGCOLOR
	IUP_WIDGET_SPACING
	IUP_WIDGET_TITLE
	IUP_WIDGET_FLAT_TEXT
		redefine
			set_alignment
		end
	IUP_WIDGET_BACK_IMAGE_2
	IUP_WIDGET_FRONT_IMAGE_2
	IUP_WIDGET_IMAGE_2
	IUP_WIDGET_PADDING
		redefine
			set_padding
		end
	IUP_WIDGET_BORDER
	IUP_WIDGET_HAS_FOCUS
	IUP_WIDGET_HIGHLIGHT
	IUP_WIDGET_PRESS
	IUP_WIDGET_FOCUSFEEDBACK

create {ANY}
	drop_button_empty,
	drop_button

feature {ANY}

	drop_button_empty
		local
			a_drop_button, p: POINTER
		do
			a_drop_button := int_drop_button(p)
			
			set_widget(a_drop_button)
		end

	drop_button (child: IUP_WIDGET)
		local
			a_drop_button: POINTER
		do
			a_drop_button := int_drop_button(child.widget)
			
			set_widget(a_drop_button)
		end

	-- Attributes

	set_alignment (horizontal, vertical: STRING)
		-- (non inheritable): horizontal and vertical alignment of the set 
		-- image+text. Possible values: "ALEFT", "ACENTER" and "ARIGHT", combined 
		-- to "ATOP", "ACENTER" and "ABOTTOM". Default: "ALEFT:ACENTER". 
		-- Alignment does not includes the padding area. 
		do
			Precursor (horizontal, vertical)
		end

	set_arrow_active (state: BOOLEAN)
		-- (non inheritable): the arrow can be disabled when the button is 
		-- enabled. If there is no drop child the arrow will be automatically 
		-- disabled.	
		do
			iup_open.set_attribute(Current, "ARROWACTIVE", boolean_to_yesno(state))
		end

	set_arrow_align (value: STRING)
		-- (non inheritable): vertical arrow alignment. Can be: TOP, CENTER or 
		-- BOTTOM. Default: CENTER.
		require
			is_valid_arrow_align(value)
		do
			iup_open.set_attribute(Current, "ARROWALIGN", value)
		end

	set_rgb_arrow_color (red: INTEGER; green: INTEGER; blue: INTEGER)
		-- color used for the arrow. Default use FGCOLOR.
		do
			iup_open.set_attribute(Current, "ARROWCOLOR",
										  rgb_to_string(red, green, blue))
		end

	set_arrow_images (state: BOOLEAN)
		-- (non inheritable): replace the drawn arrows by the following images 
		-- (attributes below). Make sure their sizes are equal or smaller than 
		-- ARROWSIZE. Default: False.
		do
			iup_open.set_attribute(Current, "ARROWIMAGES", boolean_to_yesno(state))
		end

	set_arrow_image (name: STRING)
		-- (non inheritable): Arrow image name. 
		do
			iup_open.set_attribute(Current, "ARROWIMAGE", name)
		end

	set_arrow_image_highlight (name: STRING)
		-- (non inheritable): Arrow image name of the element in highlight state. 
		-- If it is not defined then the ARROWIMAGE is used.
		do
			iup_open.set_attribute(Current, "ARROWIMAGEHIGHLIGHT", name)
		end

	set_arrow_image_inactive (name: STRING)
		-- (non inheritable): Arrow image name of the element when inactive. If 
		-- it is not defined then the ARROWIMAGE is used and its colors will be 
		-- replaced	by a modified version creating the disabled effect. 
		do
			iup_open.set_attribute(Current, "ARROWIMAGEINACTIVE", name)
		end

	set_arrow_image_press (name: STRING)
		-- (non inheritable): Arrow image name of the element in pressed state. 
		-- If it is not defined then the ARROWIMAGE is used.
		do
			iup_open.set_attribute(Current, "ARROWIMAGEPRESS", name)
		end

	set_arrow_padding (value: INTEGER)
		-- (non inheritable): internal margin for the arrow. It is inside 
		-- ARROWSIZE. Default:	5.
		require
			value >= 0
		do
			iup_open.set_attribute(Current, "ARROWPADDING", value.out)
		end

	set_arrow_size (value: INTEGER)
		-- (non inheritable): size of the area occupied by the arrow, even when 
		-- using images. Default: 24
		require
			value >= 0
		do
			iup_open.set_attribute(Current, "ARROWSIZE", value.out)
		end

	set_border (state: BOOLEAN)
		-- (creation only): Shows a border around the canvas. Default: "False".
		do
			Precursor (state)
		end

	set_can_focus (state: BOOLEAN)
		-- (creation only) (non inheritable): enables the focus traversal of the 
		-- control. In Windows the button will respect CANFOCUS in opposite to 
		-- the other controls. Default: True.
		do
			Precursor (state)
		end

	set_drop_child (name: STRING)
		-- the name of the element that will be displayed when dropped. The drop 
		-- dialog, were the drop child is inserted, is available right after 
		-- setting the attribute using "get_dialog" on the drop child widget. See 
		-- the Notes bellow for more information.
		do
			iup_open.set_attribute(Current, "DROPCHILD", name)
		end

	set_drop_child_widget (child: IUP_WIDGET)
		-- same as DROPCHILD but directly using the widget of the element.
		do
			iup_open.set_attribute_widget(Current, "DROPCHILD_HANDLE", child)
		end

	set_drop_on_arrow (state: BOOLEAN)
		-- (non inheritable): when enabled only clicking on the drop arrow will 
		-- show the drop child. Clicking on the remaining of the button will call 
		-- FLAT_ACTION. There will be two separates areas in the button, one for 
		-- the drop arrow and one for the regular button. When disabled there 
		-- will be only one area, and the drop child will be show any where the 
		-- button is clicked, the callback FLAT_ACTION will not be called. 
		-- Default: True.
		do
			iup_open.set_attribute(Current, "DROPONARROW", boolean_to_yesno(state))
		end

	set_drop_position (pos: STRING)
		-- (non inheritable): the drop child can be shown in four different 
		-- positions relative to the drop button: BOTTOMLEFT, TOPLEFT, 
		-- BOTTOMRIGHT, TOPRIGHT. BOTTOMLEFT the top-left corner of the drop 
		-- child is aligned with the bottom-left corner of the drop button, 
		-- BOTTOMRIGHT the top-right corner of the drop child is aligned with the 
		-- bottom-right corner of the drop button, TOPLEFT the bottom-left corner 
		-- of the drop child is aligned with the top-left corner of the drop 
		-- button, TOPRIGHT the bottom-right corner of the drop child is aligned 
		-- with the top-right corner of the drop button. Default: BOTTOMLEFT.
		require
			is_valid_drop_position(pos)
		do
			iup_open.set_attribute(Current, "DROPPOSITION", pos)
		end

	set_expand (type: STRING)
		-- (non inheritable): The default value is "False". 
		do
			Precursor (type)
		end

	set_padding (horizontal, vertical: INTEGER)
		-- Internal margin. Works just like the MARGIN attribute of the IUP_HBOX 
		-- and IUP_VBOX containers, but uses a different name to avoid 
		-- inheritance problems. Alignment does not includes the padding area.
		--  Default value: "3x3".
		do
			Precursor (horizontal, vertical)
		end

	set_show_drop_down (state: BOOLEAN)
		-- opens or closes the dropdown child. Ignored if set before map.
		do
			iup_open.set_attribute(Current, "SHOWDROPDOWN", boolean_to_yesno(state))
		end

	set_visible_columns (value: INTEGER)
		-- Defines the number of visible columns for the Natural Size, this means 
		-- that will act also as minimum number of visible columns. It uses a 
		-- wider character size then the one used for the SIZE attribute so 
		-- strings will fit better without the need of extra columns. Padding 
		-- will be around the visible columns.
		require
			value > 0
		do
			iup_open.set_attribute(Current, "VISIBLECOLUMNS", value.out)
		end

	-- Extra callbacks

	set_cb_flat_action (act: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON], STRING])
		-- Action generated when the button 1 (usually left) is selected. This 
		-- callback is called only after the mouse is released and when it is 
		-- released inside the button area. Called only when 
		-- set_drop_on_arrow=True
		--
		--	ih: identifier of the element that activated the event.
		--
		-- Returns: IUP_CLOSE will be processed.
		local
			operation: INTEGER
		do
			cb_flat_action := act

			if cb_flat_action /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "FLAT_ACTION", "Fnff", operation)
		end

	set_cb_drop_down (act: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON, INTEGER], STRING])
		-- Action generated right before the drop child is shown or hidden.
		--
		-- ih: identifier of the element that activated the event.
		-- state: the new state of the drop child 1=to be shown, 0=to be hidden.
		local
			operation: INTEGER
		do
			cb_dropdown := act

			if cb_dropdown /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "DROPDOWN_CB", "NONEEDED", operation)
		end

	set_cb_drop_show (act: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON, INTEGER], STRING])
		-- Action generated right after the drop child is shown or hidden.
		--
		-- ih: identifier of the element that activated the event.
		-- state: the current state of the drop child 1=shown, 0=hidden.
		local
			operation: INTEGER
		do
			cb_dropdown := act

			if cb_dropdown /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "DROPDOWN_CB", "NONEEDED", operation)
		end

	----------------------

	set_cb_flat_button (act: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON, INTEGER, INTEGER, INTEGER, INTEGER, STRING], STRING])
		-- Action generated when any mouse button is pressed and when it is 
		-- released. Both calls occur before the ACTION callback when button 1 is 
		-- being used.
		-- IUP_CANVAS: identifies the element that activated the event.
		-- button: identifies the activated mouse button:
		--
		-- 1 - left mouse button (button 1);
		-- 2 - middle mouse button (button 2);
		-- 3 - right mouse button (button 3).
		--
		-- pressed: indicates the state of the button:
		--
		-- 0 - mouse button was released;
		-- 1 - mouse button was pressed.
		-- 
		-- x, y: position in the canvas where the event has occurred, in pixels.
		--
		-- status: status of the mouse buttons and some keyboard keys at the 
		-- moment the event is generated. The following macros must be used for 
		-- verification:
		--
		-- Returns: IUP_CLOSE will be processed. On some controls if IUP_IGNORE 
		-- is returned the action is ignored (this is system dependent).
		local
			operation: INTEGER
		do
			cb_flat_button := act

			if cb_flat_button /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "FLAT_BUTTON_CB", "NONEEDED", operation)
		end

	set_cb_flat_motion (act: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON, INTEGER, INTEGER, STRING], STRING])
		-- Action generated when the mouse moves.
		-- ih: identifier of the element that activated the event.
		-- x, y: position in the canvas where the event has occurred, in pixels.
		-- status: status of mouse buttons and certain keyboard keys at the 
		-- moment the event was generated. The same macros used for BUTTON_CB can 
		-- be used for this status.
		local
			operation: INTEGER
		do
			cb_flat_motion := act

			if cb_flat_motion /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "FALT_MOTION_CB", "NONEEDED", operation)
		end

	set_cb_flat_focus (act: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON, INTEGER], STRING])
		-- Called when the canvas gets or looses the focus. It is called after 
		-- the common callbacks GETFOCUS_CB and KILL_FOCUS_CB.
		-- ih: identifier of the element that activated the event.
		-- focus: is non zero if the canvas is getting the focus, is zero if it 
		-- is loosing the focus.
		local
			operation: INTEGER
		do
			cb_flat_focus := act

			if cb_focus /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "FLAT_FOCUS_CB", "NONEEDED", operation)
		end

	set_cb_flat_enter_window (act: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON], STRING])
		-- Action generated when the mouse enters the native element. 
		local
			operation: INTEGER
		do
			cb_flat_enterwindow := act

			if cb_enterwindow /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "FLAT_ENTERWINDOW_CB", "NONEEDED", operation)
		end

	set_cb_flat_leave_window (act: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON], STRING])
		-- Action generated when the mouse leaves the native element.
		local
			operation: INTEGER
		do
			cb_flat_leavewindow := act

			if cb_leavewindow /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "FLAT_LEAVEWINDOW_CB", "NONEEDED", operation)
		end

	-- Validations
	
	is_valid_drop_position (value: STRING): BOOLEAN
		do
			if value.is_equal("BOTTOMLEFT") or
				value.is_equal("TOPLEFT") or
				value.is_equal("BOTTOMRIGHT") or
				value.is_equal("TOPRIGHT") then
				Result := True
			else
				Result := False
			end
		end

	is_valid_arrow_align (value: STRING): BOOLEAN
		do
			if value.is_equal("TOP") or
				value.is_equal("CENTER") or
				value.is_equal("BOTTOM") then
				Result := True
			else
				Result := False
			end
		end

feature {IUP}

	-- Callbacks

	execute_flat_action: STRING
		do
			if attached cb_flat_action as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_dropdown (state: INTEGER): STRING
		do
			if attached cb_dropdown as int_cb then
				Result := int_cb.item([Current, state])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_dropshow (state: INTEGER): STRING
		do
			if attached cb_dropshow as int_cb then
				Result := int_cb.item([Current, state])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_flat_button (btn, pressed, x, y: INTEGER; status: STRING): STRING
		do
			if attached cb_flat_button as int_cb then
				Result := int_cb.item([Current, btn, pressed, x, y, status])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_flat_motion (x, y: INTEGER; status: STRING): STRING
		do
			if attached cb_flat_motion as int_cb then
				Result := int_cb.item([Current, x, y, status])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_flat_focus (focus: INTEGER): STRING
		do
			if attached cb_flat_focus as int_cb then
				Result := int_cb.item([Current, focus])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_flat_enterwindow: STRING
		do
			if attached cb_flat_enterwindow as int_cb then 
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_flat_leavewindow: STRING
		do
			if attached cb_flat_leavewindow as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

feature {NONE}

	cb_flat_action: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON], STRING]
	cb_dropdown: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON, INTEGER], STRING]
	cb_dropshow: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON, INTEGER], STRING]
	cb_flat_button: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON, INTEGER, INTEGER, INTEGER, INTEGER, STRING], STRING]
	cb_flat_motion: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON, INTEGER, INTEGER, STRING], STRING]
	cb_flat_focus: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON, INTEGER], STRING]
	cb_flat_enterwindow: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON], STRING]
	cb_flat_leavewindow: detachable FUNCTION[TUPLE[IUP_DROP_BUTTON], STRING]

	-- Internals
	
	int_drop_button (child: POINTER): POINTER
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"return IupDropButton ($child);"
      end

end -- class IUP_DROP_BUTTON

-- The MIT License (MIT)

-- Copyright (c) 2019, 2020 by German A. Arias

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in 
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
